package com.example.opengldemo.simpleGame.special;

import android.opengl.GLES30;

import java.util.ArrayList;

import com.example.opengldemo.simpleGame.MatrixState.MatrixState3D;
import com.example.opengldemo.simpleGame.special.ParticleSingle.*;


import static com.example.opengldemo.simpleGame.constant.SourceConstant.*;
import static com.example.opengldemo.simpleGame.special.ParticleDataConstant.*;

public class ParticleSystem implements Comparable<ParticleSystem>
{

	public ArrayList<ParticleSingle> alFsp=new ArrayList<ParticleSingle>();

	ArrayList<ParticleSingle> alFspForDel=new ArrayList<ParticleSingle>();

	public ArrayList<ParticleSingle> alFspForDraw=new ArrayList<ParticleSingle>();

	public ArrayList<ParticleSingle> alFspForDrawTemp=new ArrayList<ParticleSingle>();

	Object lock=new Object();
 	public float[] startColor;

	public float[] endColor;

	public int srcBlend;

	public int dstBlend;

	public int blendFunc;

	public float maxLifeSpan;

	public float lifeSpanStep;

	public int sleepSpan;

	public int groupCount;

	public float sx;
	public float sy;

	float positionX;
	float positionY;
	float positionZ;

	public float xRange;
	public float yRange;

	public float vx;
	public float vy;

	float yAngle=0;

	ParticleForDraw fpfd;

	boolean flag=true;
    public ParticleSystem(float positionx,float positiony,float positionz,ParticleForDraw fpfd)
    {
    	this.positionX=positionx;
        this.positionY=positiony;
    	this.positionZ=positionz;
    	this.startColor=START_COLOR[CURR_INDEX];
    	this.endColor=END_COLOR[CURR_INDEX];
    	this.srcBlend=SRC_BLEND[CURR_INDEX]; 
    	this.dstBlend=DST_BLEND[CURR_INDEX];
    	this.blendFunc=BLEND_FUNC[CURR_INDEX];
    	this.maxLifeSpan=MAX_LIFE_SPAN[CURR_INDEX];
    	this.lifeSpanStep=LIFE_SPAN_STEP[CURR_INDEX];
    	this.groupCount=GROUP_COUNT[CURR_INDEX];
    	this.sleepSpan=THREAD_SLEEP[CURR_INDEX];
    	this.sx=0;
    	this.sy=0;
    	this.xRange=X_RANGE[CURR_INDEX];
    	this.yRange=Y_RANGE[CURR_INDEX];
    	this.vx=0;
    	this.vy=VY[CURR_INDEX];
    	this.fpfd=fpfd;
    	
    	new Thread()
    	{
    		public void run()
    		{
    			while(flag)
    			{
    				update();
    				try 
    				{
						Thread.sleep(sleepSpan);
					} catch (InterruptedException e) 
					{
						e.printStackTrace();
					}
    			}
    		}
    	}.start();
    }
    
    public void drawSelf()
    {

        GLES30.glDisable(GLES30.GL_DEPTH_TEST);

        GLES30.glEnable(GLES30.GL_BLEND);  

         GLES30.glBlendEquation(blendFunc);

        GLES30.glBlendFunc(srcBlend,dstBlend); 
        

    	alFspForDrawTemp.clear();
    	synchronized(lock)
    	{

    	   for(int i=0;i<alFspForDraw.size();i++)
    		{
    			alFspForDrawTemp.add(alFspForDraw.get(i));
    		}
    	}
    	MatrixState3D.translate(positionX, positionY, positionZ);
    	calculateBillboardDirection();
		MatrixState3D.rotate(yAngle, 0, 1, 0);
    	for(ParticleSingle fsp:alFspForDrawTemp)
    	{
    		fsp.drawSelf(startColor,endColor,maxLifeSpan);
    	}

        GLES30.glEnable(GLES30.GL_DEPTH_TEST);

        GLES30.glDisable(GLES30.GL_BLEND);
    }
    
    public void update()
    {

    	for(int i=0;i<groupCount;i++)
    	{
    		if(SpecialBZ==5)
    		{

        		float px=(float) (sx+xRange*(Math.random()*2-1.0f));
                float py=(float) (sy+yRange*(Math.random()*2-1.0f));

    			double elevation=Math.random()*Math.PI/12+Math.PI*2/12;
    			double direction=Math.random()*Math.PI*2;

    			float vy=(float)(2f*Math.sin(elevation));	
    			float vx=(float)(2f*Math.cos(elevation)*Math.cos(direction));	
    			float vz=(float)(2f*Math.cos(elevation)*Math.sin(direction));
    			ParticleSingle fsp=new ParticleSingle(px,py,vx,vy,vz,fpfd);
    			alFsp.add(fsp);
    		}
    		if(SpecialBZ==2)
    		{

        		float px=(float) (sx+xRange*(Math.random()*2-1.0f));
                float py=(float) (sy+yRange*(Math.random()*2-1.0f));

    			double elevation=Math.random()*Math.PI/12+Math.PI*2/12;
    			double direction=Math.random()*Math.PI*2;

    			float vy=(float)(2f*Math.sin(elevation));	
    			float vx=(float)(2f*Math.cos(elevation)*Math.cos(direction));	
    			float vz=(float)(2f*Math.cos(elevation)*Math.sin(direction));
    			ParticleSingle fsp=new ParticleSingle(px,py,vx,vy,vz,fpfd);
    			alFsp.add(fsp);
    		}
//    		else{

//        		float px=(float) (sx+xRange*(Math.random()*2-1.0f));
//                float py=(float) (sy+yRange*(Math.random()*2-1.0f));
//                float vx=(sx-px)/150;

//                ParticleSingle fsp=new ParticleSingle(px,py,vx,vy,fpfd);
//                alFsp.add(fsp);
//    		}
    	}   	
    	

    	alFspForDel.clear();
    	for(ParticleSingle fsp:alFsp)
    	{

    		fsp.go(lifeSpanStep);

    		if(fsp.lifeSpan>this.maxLifeSpan)
    		{
    			alFspForDel.add(fsp);
    		}
    	}
    	

    	for(ParticleSingle fsp:alFspForDel)
    	{
    		alFsp.remove(fsp);
    	}    

    	synchronized(lock)
    	{
    		alFspForDraw.clear();
    		for(int i=0;i<alFsp.size();i++)
    		{
    			alFspForDraw.add(alFsp.get(i));
    		}
    	}
    }
	public void calculateBillboardDirection()
	{

		float xspan=positionX-EYE_X;
		float zspan=positionZ-EYE_Z;
		
		if(zspan<=0)
		{
			yAngle=(float)Math.toDegrees(Math.atan(xspan/zspan));	
		}
		else
		{
			yAngle=180+(float)Math.toDegrees(Math.atan(xspan/zspan));
		}
	}
	public int compareTo(ParticleSystem another) {

		float xs=positionX-EYE_X;
		float zs=positionZ-EYE_Z;
		
		float xo=another.positionX-EYE_X;
		float zo=another.positionZ-EYE_Z;
		
		float disA=(float)(xs*xs+zs*zs);
		float disB=(float)(xo*xo+zo*zo);
		return ((disA-disB)==0)?0:((disA-disB)>0)?-1:1;  
	}

}
